package sketch.seg.cd;

import java.awt.geom.Line2D;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import sketch.ink.SampledPoint;
import sketch.ink.Stroke;

public class CDStaticK extends CDStaticKH {

	private int K = 3;

	private double H = -1;

	public CDStaticK() {

	}

	public CDStaticK(Stroke s) {
		super(s);
	}

	private double[] rhos = null;

	public double[] getRhos() {
		if (rhos == null)
			detectCorners();
		return rhos;
	}

	public void setRhos(double[] rhos) {
		this.rhos = rhos;
	}

	public int getK() {
		return K;
	}

	public void setK(int k) {
		clear();
		K = k;
	}

	public void calcRhos() {
		SampledPoint[] ps = new SampledPoint[getPoints().size()];
		getPoints().toArray(ps);

		rhos = new double[ps.length];
		for (int i = 0; i < rhos.length; i++) {
			rhos[i]	= relativeRho(ps, i, getK());
			System.out.println(rhos[i]);
		}
	}

	public double getH() {
		if (H < 0) {
			SampledPoint[] ps = new SampledPoint[getPoints().size()];
			getPoints().toArray(ps);

			rhos = new double[ps.length];
			double sum = 0;
			for (int i = 0; i < rhos.length; i++) {
				rhos[i]	= relativeRho(ps, i, getK());
				sum += rhos[i];
			}

			double mean = sum / rhos.length;
			double d = 0;
			for (int i = 0; i < rhos.length; i++) {
				double dis = rhos[i] - mean;
				d += dis * dis;
			}
			d = d / rhos.length;

			H = mean + 6 * d;
		}
		return H;
	}

	public void setH(double h) {
		clear();
		H = h;
	}

	private List<SampledPoint> cd(List<SampledPoint> points, int K, double H) {
		List<SampledPoint> corners = new ArrayList<SampledPoint>();
		double[] rhos = new double[points.size()];

		if (points == null)
			return corners;

		SampledPoint[] ps = new SampledPoint[points.size()];
        int i1 = 0;
        for (Iterator<SampledPoint> it = points.iterator(); it.hasNext(); ) {
        	ps[i1++] = it.next();
        }

        for (int i = 0; i < ps.length; i++) {
            rhos[i] = relativeRho(ps, i, K);
        }
        setRhos(rhos);

        int maxIndex = 0;
        double maxRho = -1;
        int state = 0;
        for (int i = 0; i < rhos.length; i++) {
            if (rhos[i] > H && state == 0) {
                state = 1;
                maxRho = rhos[i];
                maxIndex = i;
            } else if (rhos[i] > H && state == 1) {
                if (rhos[i] > maxRho) {
                    maxRho = rhos[i];
                    maxIndex = i;
                }
            } else if (rhos[i] < H && state == 1) {
                state = 0;
                corners.add(ps[maxIndex]);
                maxRho = -1;
                maxIndex = 0;
            }
        }
        if (state == 1)
            corners.add(ps[maxIndex]);

		return corners;
	}

	protected void detectCorners() {
		super.detectCorners();

        rhos = new double[getPoints().size()];
        List<SampledPoint> tmp = cd(getPoints(), 3, 0.8);

//        setCorners(tmp);

//		calcRhos();
//		List<SampledPoint> tmp = new ArrayList<SampledPoint>();
//		double d[] = new double[rhos.length];
//		if (d.length > 0) {
//			d[0] = 0;
//
//			for (int i = 1; i < d.length; i++) {
//				d[i] = rhos[i] - rhos[i-1];
////				System.out.println(d[i]);
//			}
//
//
//		}
		setCorners(tmp);

	}

	public static double relativeRho(SampledPoint[] ps, int I, int K) {
        if (I < K || I >= ps.length - K)
            return 0;

        Line2D line = new Line2D.Double(ps[I-K].getX(), ps[I-K].getY(),
                ps[I+K].getX(), ps[I+K].getY());

        double dis = 0;
        double len = line.getP1().distance(line.getP2());
        for (int i = I - K + 1; i < I + K; i++) {
            dis += Math.abs(line.ptLineDist(ps[i].toPoint2D()));
        }
        return Math.abs(dis/len);
    }
}
